// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SanitizerCmdletGroup.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Extensions.Sanitizer
{
    #region Usings

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;

    using Microsoft.Build.BuildEngine;

    using Org.OpenTrader.Framework;
    using Org.OpenTrader.Framework.Cmdlet;

    #endregion

    /// <summary>
    /// The execution context command group.
    /// </summary>
    public class SanitizerCmdletGroup : CmdletGroup
    {
        #region Constants and Fields

        /// <summary>
        /// The commands.
        /// </summary>
        private readonly IDictionary<string, Cmdlet> commands;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SanitizerCmdletGroup"/> class. 
        /// Initializes a new instance of the <see cref="ReportBuilderCmdletGroup"/> class.
        /// </summary>
        public SanitizerCmdletGroup()
        {
            this.commands = new Dictionary<string, Cmdlet>();

            Cmdlet cmd;

            cmd = new ProjectsCmdlet(this);
            this.commands[cmd.Name] = cmd;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets Cmdlets.
        /// </summary>
        public override IDictionary<string, Cmdlet> Cmdlets
        {
            get
            {
                return this.commands;
            }
        }

        /// <summary>
        /// Gets Help.
        /// </summary>
        public override string Help
        {
            get
            {
                return "This command group is used to sanitize";
            }
        }

        /// <summary>
        /// Gets Name.
        /// </summary>
        public override string Name
        {
            get
            {
                return "sanitizer";
            }
        }

        #endregion

        /// <summary>
        /// The run command.
        /// </summary>
        public class ProjectsCmdlet : Cmdlet
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(MethodBase.GetCurrentMethod());

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="ProjectsCmdlet"/> class.
            /// </summary>
            /// <param name="cmdletGroup">
            /// The command group.
            /// </param>
            public ProjectsCmdlet(CmdletGroup cmdletGroup)
                : base(cmdletGroup)
            {
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets Help.
            /// </summary>
            public override string Help
            {
                get
                {
                    return "sanitize all C# projects found in directory sanitizing_directory";
                }
            }

            /// <summary>
            /// Gets Name.
            /// </summary>
            public override string Name
            {
                get
                {
                    return "csproj";
                }
            }

            /// <summary>
            /// Gets Usage.
            /// </summary>
            public override string Usage
            {
                get
                {
                    return string.Format("{0} {1} sanitizing_directory", this.CmdletGroup.Name, this.Name);
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The execute.
            /// </summary>
            /// <param name="args">
            /// The args.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status Execute(string[] args)
            {
                if (args.Length < 1)
                {
                    return Status.Failure(Identity, "parameter sanitizing_directory is missing");
                }

                var bookingPath = PathUtil.Cleanup(args[0]);

                ProjectsFixture(bookingPath);

                return Status.Success(Identity);
            }

            #endregion

            #region Methods

            /// <summary>
            /// The find projects.
            /// </summary>
            /// <param name="directory">
            /// The directory.
            /// </param>
            /// <returns>
            /// </returns>
            private static IList<string> FindProjects(string directory)
            {
                return FindProjectsRecursively(directory);
            }

            /// <summary>
            /// The find projects recursively.
            /// </summary>
            /// <param name="directory">
            /// The directory.
            /// </param>
            /// <returns>
            /// </returns>
            private static IList<string> FindProjectsRecursively(string directory)
            {
                IList<string> projectFiles = new List<string>();

                var files = from file in Directory.GetFiles(directory)
                            where file.EndsWith(".csproj", true, Constants.CultureInfo)
                            select file;

                foreach (var file in files)
                {
                    projectFiles.Add(file);
                }

                var subDirectories = Directory.GetDirectories(directory);
                foreach (var subDirectory in subDirectories)
                {
                    var subDirectoryProjects = FindProjectsRecursively(subDirectory);
                    foreach (var subDirectoryProject in subDirectoryProjects)
                    {
                        projectFiles.Add(subDirectoryProject);
                    }
                }

                return projectFiles;
            }

            /// <summary>
            /// The projects fixture.
            /// </summary>
            /// <param name="path">
            /// The path.
            /// </param>
            private static void ProjectsFixture(string path)
            {
                var projectFileNames = FindProjects(path);

                foreach (var projectFileName in projectFileNames)
                {
                    Console.WriteLine("Sanitizing " + projectFileName);
                    var engine = new Engine();
                    var project = new Project(engine);

                    project.Load(projectFileName);

                    // TODO : FIX These ones
                    // <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
                    // <RootNamespace>$prjname</RootNamespace>
                    // <AssemblyName>$prjname</AssemblyName>

                    // Rewrite "Debug" and "Release" BuildProperty groups
                    RewriteBuildPropertyGroups(project);

                    // Console.WriteLine("Fixed " + projectFileName);
                    project.Save(projectFileName);
                }
            }

            /// <summary>
            /// The rewrite build property groups.
            /// </summary>
            /// <param name="project">
            /// The project.
            /// </param>
            private static void RewriteBuildPropertyGroups(Project project)
            {
                var removeMe = new List<BuildPropertyGroup>();
                foreach (BuildPropertyGroup propertyGroup in project.PropertyGroups)
                {
                    if (!string.IsNullOrEmpty(propertyGroup.Condition) && !propertyGroup.IsImported &&
                        propertyGroup.Condition.IndexOf("$(Configuration)|$(Platform)") > 0)
                    {
                        removeMe.Add(propertyGroup);
                    }
                }

                foreach (var pg in removeMe)
                {
                    project.RemovePropertyGroup(pg);
                }

                var debugPropertyGroup = project.AddNewPropertyGroup(false);
                debugPropertyGroup.Condition = "'$(Configuration)|$(Platform)' == 'Debug|OpenTrader_x86'";
                debugPropertyGroup.AddNewProperty("DebugSymbols", @"true");
                debugPropertyGroup.AddNewProperty("DebugType", @"full");
                debugPropertyGroup.AddNewProperty("Optimize", @"false");
                debugPropertyGroup.AddNewProperty("DefineConstants", @"TRACE;DEBUG;X86");
                debugPropertyGroup.AddNewProperty("ErrorReport", @"prompt");
                debugPropertyGroup.AddNewProperty("WarningLevel", @"4");
                debugPropertyGroup.AddNewProperty("PlatformTarget", @"x86");
                debugPropertyGroup.AddNewProperty("OutputPath", @"_OpenTrader_x86_\Debug");
                debugPropertyGroup.AddNewProperty("UseVSHostingProcess", @"true");

                var releasePropertyGroup = project.AddNewPropertyGroup(false);
                releasePropertyGroup.Condition = "'$(Configuration)|$(Platform)' == 'Release|OpenTrader_x86'";
                releasePropertyGroup.AddNewProperty("DebugSymbols", @"none");
                releasePropertyGroup.AddNewProperty("Optimize", @"true");
                releasePropertyGroup.AddNewProperty("DefineConstants", @"TRACE;X86");
                releasePropertyGroup.AddNewProperty("ErrorReport", @"prompt");
                releasePropertyGroup.AddNewProperty("WarningLevel", @"4");
                releasePropertyGroup.AddNewProperty("PlatformTarget", @"x86");
                releasePropertyGroup.AddNewProperty("OutputPath", @"_OpenTrader_x86_\Release");
                releasePropertyGroup.AddNewProperty("UseVSHostingProcess", @"false");

                var debugPropertyGroup64 = project.AddNewPropertyGroup(false);
                debugPropertyGroup64.Condition = "'$(Configuration)|$(Platform)' == 'Debug|OpenTrader_x64'";
                debugPropertyGroup64.AddNewProperty("DebugSymbols", @"true");
                debugPropertyGroup64.AddNewProperty("DebugType", @"full");
                debugPropertyGroup64.AddNewProperty("Optimize", @"false");
                debugPropertyGroup64.AddNewProperty("DefineConstants", @"TRACE;DEBUG;X64");
                debugPropertyGroup64.AddNewProperty("ErrorReport", @"prompt");
                debugPropertyGroup64.AddNewProperty("WarningLevel", @"4");
                debugPropertyGroup64.AddNewProperty("PlatformTarget", @"x64");
                debugPropertyGroup64.AddNewProperty("OutputPath", @"_OpenTrader_x64_\Debug");
                debugPropertyGroup64.AddNewProperty("UseVSHostingProcess", @"true");

                var releasePropertyGroup64 = project.AddNewPropertyGroup(false);
                releasePropertyGroup64.Condition = "'$(Configuration)|$(Platform)' == 'Release|OpenTrader_x64'";
                releasePropertyGroup64.AddNewProperty("DebugSymbols", @"false");
                releasePropertyGroup64.AddNewProperty("Optimize", @"true");
                releasePropertyGroup64.AddNewProperty("DefineConstants", @"TRACE;X64");
                releasePropertyGroup64.AddNewProperty("ErrorReport", @"prompt");
                releasePropertyGroup64.AddNewProperty("WarningLevel", @"4");
                releasePropertyGroup64.AddNewProperty("PlatformTarget", @"x64");
                releasePropertyGroup64.AddNewProperty("OutputPath", @"_OpenTrader_x64_\Release");
                releasePropertyGroup64.AddNewProperty("UseVSHostingProcess", @"false");

                var debugPropertyGroupAnyCpu = project.AddNewPropertyGroup(false);
                debugPropertyGroupAnyCpu.Condition = "'$(Configuration)|$(Platform)' == 'Debug|OpenTrader_AnyCPU'";
                debugPropertyGroupAnyCpu.AddNewProperty("DebugSymbols", @"true");
                debugPropertyGroupAnyCpu.AddNewProperty("DebugType", @"full");
                debugPropertyGroupAnyCpu.AddNewProperty("Optimize", @"false");
                debugPropertyGroupAnyCpu.AddNewProperty("DefineConstants", @"TRACE;DEBUG;AnyCPU");
                debugPropertyGroupAnyCpu.AddNewProperty("ErrorReport", @"prompt");
                debugPropertyGroupAnyCpu.AddNewProperty("WarningLevel", @"4");
                debugPropertyGroupAnyCpu.AddNewProperty("PlatformTarget", @"AnyCPU");
                debugPropertyGroupAnyCpu.AddNewProperty("OutputPath", @"_OpenTrader_AnyCPU_\Debug");
                debugPropertyGroupAnyCpu.AddNewProperty("UseVSHostingProcess", @"true");

                var releasePropertyGroupAnyCpu = project.AddNewPropertyGroup(false);
                releasePropertyGroupAnyCpu.Condition = "'$(Configuration)|$(Platform)' == 'Release|OpenTrader_AnyCPU'";
                releasePropertyGroupAnyCpu.AddNewProperty("DebugSymbols", @"false");
                releasePropertyGroupAnyCpu.AddNewProperty("Optimize", @"true");
                releasePropertyGroupAnyCpu.AddNewProperty("DefineConstants", @"TRACE;AnyCPU");
                releasePropertyGroupAnyCpu.AddNewProperty("ErrorReport", @"prompt");
                releasePropertyGroupAnyCpu.AddNewProperty("WarningLevel", @"4");
                releasePropertyGroupAnyCpu.AddNewProperty("PlatformTarget", @"AnyCPU");
                releasePropertyGroupAnyCpu.AddNewProperty("OutputPath", @"_OpenTrader_AnyCPU_\Release");
                releasePropertyGroupAnyCpu.AddNewProperty("UseVSHostingProcess", @"false");
            }

            #endregion
        }
    }
}